﻿// Copyright (c)  YISH. All rights reserved.
// Licensed under the MIT License, See License.txt in the project root for license information.

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using NSQL.Query.Extensions;

namespace NSQL.Query
{
    public static class ExpressionBuilder
    {
        private static MethodBase GetGenericMethod(IReflect type, string methodName, Type[] typeArgs,
            Type[] argTypes, BindingFlags flags)
        {
            var argumentCount = typeArgs.Length;
            var methods = type.GetMethods(flags)
                .Where(m => m.Name == methodName && m.GetGenericArguments().Length == argumentCount)
                .Select(m => m.MakeGenericMethod(typeArgs)).ToArray<MethodBase>();

            return Type.DefaultBinder.SelectMethod(flags, methods, argTypes, null);
        }
        
        
        public static Expression Any(Expression collection, Expression predicate)
        {
            var cType = collection.Type.GetImplementedIEnumerableType();
            collection = Expression.Convert(collection, cType);

            var elemType = cType.GetGenericArguments()[0];
            var predType = typeof(Func<,>).MakeGenericType(elemType, typeof(bool));

            // Enumerable.Any<T>(IEnumerable<T>, Func<T,bool>)
            var anyMethod = (MethodInfo) GetGenericMethod(
                typeof(Enumerable), nameof(Any),
                new[] {elemType},
                new[] {cType, predType},
                BindingFlags.Static | BindingFlags.Public);

            return Expression.Call(anyMethod, collection, predicate);
        }
    }
}